<?php
/**
 * Manage exchange between 2 members or mass payment on association account
 *
 * @package    letsManager
 * @subpackage letsExchange
 * @author     Jerome Fouilloy
 * @version    SVN: $Rev$
 */
class letsExchangeActions extends sfActions
{

  public function executeIndex(sfWebRequest $request)
  {
    $asso_id = $this->getUser()->getAssociationId();
    $page = $request->getParameter('page', 1);
    $this->echangesPager = LetsExchangeTable::getPagerEnabledForAssociation($asso_id,$page);
    $this->getUser()->setCurrentReferer('@lets_exchange_list');
  }
  
  public function executeListByUser(sfWebRequest $request)
  {
    $myId = $this->getUser()->getUserId();
    $memberId = intval($request->getParameter('member_id',$myId));
    $page = intval($request->getParameter('page', 1));
    
    $this->titleExchanges = 'Liste de mes échanges validés';
    $this->titlePending = 'Les échanges en attente de votre partenaire';
    if($memberId != $myId)
    {
      LetsManagerRights::checkRightRedirect(LetsManagerRights::SEE_EXCHANGES_LIST,$this,'@lets_home_member');
      
      $this->titleExchanges ='Liste des échanges de '. LetsMemberTable::getNameById($memberId,false);
      $this->titlePending = 'Les échanges en attente du partenaire';
    }
    $this->echangesPager = LetsExchangeTable::getPagerForMemberId($memberId,$page);
    $this->exchangesPending = LetsExchangeTable::getExchangesNotValidatedForMember($memberId);
  }
  
  public function executeShowManager(sfWebRequest $request)
  {
    $id = intval($request->getParameter('id',-1));
    $this->forward404Unless($this->echange = LetsExchangeTable::getInstance()->find($id));

  }
  
  public function executeMembersStats(sfWebRequest $request)
  {
    $asso_id = $this->getUser()->getAssociationId();
    $this->membersStats = LetsExchangeTable::generateStatsForMember($asso_id);
  }
  
  public function executeAssociationStats(sfWebRequest $request)
  {
    $this->stats = AssociationExchangeStats::generateStatsForAssociation($this->getUser()->getAssociationId());
  }
  
  /*
   * MANAGER ACTIONS
   */
  public function executeNewByManager(sfWebRequest $request)
  {
    // there is 2 cases : member has right to add exchange for other or member has
    // right uses association's money
    $this->form = new LetsExchangeForm();
    $this->setTemplate('new');
    $this->is_manager = true;
    // member can only add exchange for association
    $this->can_select_debitor = $this->getUser()->hasPermission(LetsManagerRights::ADD_EXCHANGE_OTHERS);
  }
  
  /**
   * Creating new exchange
   */
  public function executeCreateByManager(sfWebRequest $request)
  {
    $this->form = new LetsExchangeForm();
    $this->processFormManager($request, $this->form, new LetsExchange());
    $this->setTemplate('new');
    $this->is_manager = true;
    // member can only add exchange for association
    $this->can_select_debitor = $this->getUser()->hasPermission(LetsManagerRights::ADD_EXCHANGE_OTHERS);
  }

  public function executeEditByManager(sfWebRequest $request)
  {
    $id = $request->getParameter('id');
    $this->forward404Unless($echange = LetsExchangeTable::getInstance()->find($id));
    $this->forward404Unless($echange->canEdit($this->getUser()));
    $this->form = new LetsExchangeForm($echange);

    $this->creditor_member = $echange->getCreditorUser();
    $this->debitor_member = $echange->getDebitorUser();
    $this->date_exchange = $echange->getCreatedAt();
    $this->setTemplate('edit');
    $this->is_manager = true;
  }
  
  public function executeUpdateByManager(sfWebRequest $request)
  {
    $this->forward404Unless($request->isMethod('post') || $request->isMethod('put'));
    $id = $request->getParameter('id');
    $this->forward404Unless($echange = LetsExchangeTable::getInstance()->find($id));
    $this->form = new LetsExchangeForm($echange);
    $this->processFormManager($request, $this->form, $echange);
    $this->setTemplate('edit');
    $this->is_manager = true;
  }
  
  public function executeDelete(sfWebRequest $request)
  {
    $id = $request->getParameter('id');
    $this->forward404Unless($echange = LetsExchangeTable::getInstance()->find($id));
    $canDeleteExchangesOthers = $this->getUser()->hasCredential(LetsManagerRights::MANAGE_EXCHANGE_OTHERS);

    $echange->delete();
  }
  /*
   * MEMBER ACTIONS
   */
  public function executeNewByUser(sfWebRequest $request)
  {
    $this->form = new LetsExchangeUserForm();
    $this->setTemplate('new');

  }

  public function executeCreateByUser(sfWebRequest $request)
  {
    $this->form = new LetsExchangeUserForm();
    $this->processFormUser($request, $this->form, new LetsExchange());
    $this->setTemplate('new');
    
  }

  public function executeEditByUser(sfWebRequest $request)
  {
    $id = $request->getParameter('id');
    $this->forward404Unless($echange = LetsExchangeTable::getInstance()->find($id));
    $this->forward404Unless($echange->canEdit($this->getUser()));
    $this->form = new LetsExchangeUserForm($echange);
    $this->other_member = $echange->getPartnerMember($this->getUser()->getUserId());

    $this->setTemplate('edit');
  }

  public function executeUpdateByUser(sfWebRequest $request)
  {
    $this->forward404Unless($request->isMethod('post') || $request->isMethod('put'));
    $id = $request->getParameter('id');
    $this->forward404Unless($echange = LetsExchangeTable::getInstance()->find($id));
    $this->form = new LetsExchangeUserForm($echange);
    $this->processFormUser($request, $this->form, $echange);
    $this->setTemplate('edit');
  }
  /*
   * Validation actions
   */
  /**
   * Validate one exchange for the current logged member
   * @param sfWebRequest $request
   */
  public function executeValidateOne(sfWebRequest $request)
  {
    $id = intval($request->getParameter('id',-1));
    $state = $request->getParameter('state', null);
    $currentUserId = $this->getUser()->getUserId();

    $exchange = LetsExchangeTable::getInstance()->find($id);
    $this->forward404Unless($exchange);
    	
    $debitorAccountId = $exchange->getDebitorId();
    $creditorAccountId = $exchange->getCreditorId();

    $myAccountId = LetsMoneyAccountTable::getAccountByMemberId($currentUserId);

    $canManageExchanges = $this->getUser()->hasCredential(LetsManagerRights::MANAGE_EXCHANGE_OTHERS);

    // manager can validate all exchanges
    if($canManageExchanges)
    {
      $canModify = true;
    }
    else
    {
      // creator user cannot modify state and the user must be creditor or debitor
      $canModify = ($exchange->getCreatedBy() != $currentUserId) && !$exchange->isValidated() &&
          ($debitorAccountId == $myAccountId || $creditorAccountId == $myAccountId);
    }
    // check argument is valid
    $this->forward404Unless($canModify == true && 
      ($state === LetsExchangeTable::STATE_ACCEPTED || $state === LetsExchangeTable::STATE_REFUSED),'Right insufficient');
      
    $this->validateExchange($exchange,$state,$currentUserId);
    $this->redirect($this->getUser()->getCurrentReferer('@lets_home_member'));
  }
  /**
   * Validate one exchange from email received with unique link
   * @param sfWebRequest $request
   */
  public function executeValidateLink(sfWebRequest $request)
  {
    $key = $request->getParameter('unique_key',null);
    $memberId = $request->getParameter('member_id',null);
    $this->error = null;
    if($key == null || $memberId == null || $key == '')
    {
      $this->error = 'Lien de validation invalide';
    }
    else {
      $this->exchange = LetsExchangeTable::getExchangeForUniqueKey($key);

      if($this->exchange == null)
      {
        $this->error = "Pas d'échange a validé pour ce lien ou l'échange a déjà été validé.";
      }
      else{
        $this->partner = $this->exchange->getPartnerMember($memberId);
        // the validator is not the creator 
        $this->validateExchange($this->exchange,LetsExchangeTable::STATE_ACCEPTED,$memberId);
      }
    }
    $this->setLayout('no_menu');
  }
  
  protected function validateExchange(LetsExchange $exchange,$state,$currentUserId)
  {
    $exchange->setStateValidation($state);
    $exchange->setDateValidation(date('Y-m-d'));
    $exchange->save();
    
    $myMember = LetsMemberTable::getById($currentUserId);
    $partnerMember = $exchange->getPartnerMember($currentUserId);
    // notify partner of exchange accepted
    if($state == LetsExchangeTable::STATE_ACCEPTED)
    {
      $paymentType = $exchange->getPaymentTypeString($partnerMember->getId());
      $strPaymentType = ($paymentType == LetsExchangeTable::PAYMENT_NAME ? 'débité' : 'crédité');

      $mailValues = array();
      $mailValues['partner'] = $myMember;
      $mailValues['exchange.payment_type'] = $strPaymentType;
      $mailValues['exchange.name'] = $exchange->getName();
      $mailValues['exchange.amount'] = $exchange->getAmount();
      $mailValues['exchange.category'] = $exchange->getCategory()->getName();
      $mailValues['exchange.money_name'] = LetsConfiguration::moneyName($myMember->getAssociationId());
      
      MailerFactory::loadTemplateAndSend($currentUserId,$partnerMember,LetsManagerEmails::KEY_EXCHANGE_ACCEPTED,$mailValues);
    }
    // check money alarm
    self::checkMoneyAvailableForMember($myMember);
    self::checkMoneyAvailableForMember($partnerMember);
    	
    $this->getUser()->setFlash('notice',"Validation de l'échange N°".$exchange->getId()." enregistré.");
    
  }
  /**
   * Validate all exchanges pending for the current user logged
   * FUNC: validate several exchanges but not all with checkbox selection in table
   * @param sfWebRequest $request
   */
  public function executeValidateMany(sfWebRequest $request)
  {
    $state = $request->getParameter('state', null);
    $user_id = $request->getParameter('user_id',-1);
    if($user_id == -1)
    {
      $user_id = $this->getUser()->getUserId();
    }
    $this->forward404Unless($state == LetsExchangeTable::STATE_ACCEPTED || $state == LetsExchangeTable::STATE_REFUSED);
    	
    $exchanges = LetsExchangeTable::getExchangesPendingForMember($user_id);
    	
    // avoid sent several times the alarm email to the same partner
    $alarmEmailSent = array();
    	
    foreach($exchanges as $exchange)
    {
      $exchange->setStateValidation($state);
      $exchange->setDateValidation(date('Y-m-d'));
      $exchange->save();
      // check money on partner
      if($exchange->isAccepted())
      {
        $partner = $exchange->getPartnerMember($user_id);
        if(!array_key_exists($partner->getId(),$alarmEmailSent) && self::checkMoneyAvailableForMember($partner) )
        {
          $alarmEmailSent[$partner->getId()] = $partner;
        }
      }
    }
    // check the current member
    self::checkMoneyAvailableForMember(LetsMemberTable::getById($user_id));
    	
    $this->getUser()->setFlash('notice',"Etat des échanges enregistrés");
    $this->redirect('@lets_home_member');
  }
  /**
   * Display mass payment form
   * @param sfWebRequest $request
   */
  public function executeMassPayment(sfWebRequest $request)
  {
    $this->form = new LetsMassPaymentForm();
    $asso_id = $this->getUser()->getAssociationId();
    $this->associationMemberId = LetsConfiguration::memberIdForAssociation($asso_id);
    $this->membersCount = LetsMemberTable::doCount($asso_id);
  }
  /**
   * Do mass payment on all members
   * @param sfWebRequest $request
   */
  public function executeMassPaymentCreate(sfWebRequest $request)
  {
    $this->forward404Unless($request->isMethod('post') || $request->isMethod('put'));
    $this->form = new LetsMassPaymentForm();
    $this->form->bind($request->getParameter($this->form->getName()));
    $asso_id = $this->getUser()->getAssociationId();
    if($this->form->isValid())
    {
      $values = $this->form->getValues();

      $members = LetsMemberTable::getEnabledForAssociation($asso_id);

      $moneyAccountAssociation = LetsConfiguration::moneyAccountForAssociation($asso_id);
      // problem configuration
      if($moneyAccountAssociation == null)
      {
        LetsConfiguration::redirectErrorConfig($this,LetsConfiguration::ASSOCIATION_MEMBER_USERNAME,"La variable n'est pas configuré");
      }
      foreach($members as $member)
      {
        $echange = new LetsExchange();
        $memberAcountId = LetsMoneyAccountTable::getAccountIdByMemberId($member->getId());
        // credit member and debit association
        if($values['type'] == LetsMassPaymentForm::PAYMENT_CREDIT)
        {
          $echange->setDebitorId($moneyAccountAssociation->getId());
          $echange->setCreditorId($memberAcountId);
        }
        // debit member and credit association
        else
        {
          $echange->setCreditorId($moneyAccountAssociation->getId());
          $echange->setDebitorId($memberAcountId);
        }
        $echange->setName($values['name']);
        $echange->setCategoryId($values['category_id']);
        $echange->setAmount($values['amount']);
        $echange->setCreatedBy($this->getUser()->getUserId());
        $echange->setStateValidation(LetsExchangeTable::STATE_ACCEPTED);
        $echange->setDateValidation(date('Y-m-d'));
        $echange->save();
      }

      $this->getUser()->setFlash('notice','Paiement de masse effectué');
      $this->redirect('@lets_exchange_list');
    }
    else{
      $this->associationMemberId = LetsConfiguration::memberIdForAssociation($asso_id);
      $this->membersCount = LetsMemberTable::doCount($asso_id);
      $this->setTemplate('massPayment');
    }
  }
  /*
   * Utils functions
   */
  /**
   * Check if the member has overflow the alarm limit, send email in this case
   * @param Member $member
   * @return true if email has sent, false otherwise
   */
  protected function checkMoneyAvailableForMember(Member $member)
  {
    $assoId = $member->getAssociationId();
    $memberIdAsso = LetsConfiguration::memberIdForAssociation($assoId);
    // we don't check the association money
    if($memberIdAsso == $member->getId())
    {
      return false;
    }
    // call this function after register exchange we check the current amount of member
    $money = LetsMoneyAccountTable::getMoneyAvailable($member->getId());
    $alarmMaxi = LetsConfiguration::moneyAlarmMaxi($assoId);
    $alarmMini = LetsConfiguration::moneyAlarmMini($assoId);
    $params = array();
    $params['association.alarm_maxi'] = $alarmMaxi;
    $params['association.alarm_mini'] = $alarmMini;
    $params['association.money_name'] = LetsConfiguration::moneyName($assoId);
    $params['member'] = $member;
    $params['member.money_available'] = $money;
    if($money < $alarmMini)
    {
      $this->_mailAlarmToReceivers($member,LetsManagerEmails::KEY_ALARM_MEMBER_MINI,$assoId,$params);
      return true;
    }
    else if($money  > $alarmMaxi)
    {
      $this->_mailAlarmToReceivers($member,LetsManagerEmails::KEY_ALARM_MEMBER_MAXI,$assoId,$params);
      return true;
    }
    return false;
  }
  /**
   * Send alarm email to reveicers configured in application
   * @param Member $member the member created alarm
   * @param string $templateKey the template to use
   * @param integer $asso_id association id
   */
  private function _mailAlarmToReceivers(Member $member,$templateKey,$asso_id,$params)
  {
    $recipients = LetsConfiguration::membersForAlarmMoney($asso_id);
    foreach($recipients as $receiver)
    {
      MailerFactory::loadTemplateAndSend($this->getUser()->getUserId(),$receiver,$templateKey,$params);
    }
    
    // notify member he has to overflow the limit for association
    MailerFactory::loadTemplateAndSend($this->getUser()->getUserId(),$member,LetsManagerEmails::KEY_ALARM_THE_MEMBER,$params);
    
  }

  protected function processFormUser(sfWebRequest $request, sfForm $form, LetsExchange $exchange = null)
  {
    $form->bind($request->getParameter($form->getName()));
    if ($this->form->isValid())
    {
      $isExchangeCreation = $exchange->isNew();
      	
      $values = $this->form->getValues();
      $myUserId = $this->getUser()->getUserId();
      	
      $exchange->setCategoryId($values['category_id']);
      $exchange->setName($values['name']);
      $amount = intval($values['amount']);
      $exchange->setAmount(abs($amount));
      $msgDisplay='';
      // partner id and payment type cannot be modified
      if($isExchangeCreation)
      {
        $typePayment = $values['type'];

        $myMember= MemberTable::getById($myUserId);
        $otherMember = LetsMemberTable::getById($values['other_user_id']);
        	
        $otherMemberAccountId = LetsMoneyAccountTable::getAccountIdByMemberId($otherMember->getId());
        $myMemberAccountId = LetsMoneyAccountTable::getAccountIdByMemberId($myUserId);
        if($typePayment == LetsExchangeTable::TYPE_REQUEST)
        {
          $exchange->setDebitorId($otherMemberAccountId);
          $exchange->setCreditorId($myMemberAccountId);
        }
        else{
          $exchange->setDebitorId($myMemberAccountId);
          $exchange->setCreditorId($otherMemberAccountId);
        }
        // generate key validation
        $uniqueKey = $this->generateValidationKey($exchange);
        $exchange->setUniqueKey($uniqueKey);
        $exchange->setCreatedBy($myUserId);
        
        $exchange->setDateExchange($values['date_exchange']);
        // direct validation by the partner without email notification
        if(isset($values['partner_password']) && $values['partner_password'] != '')
        {
          $passwordValid = $otherMember->getUserGuard()->checkPassword($values['partner_password']);
          if($passwordValid == true)
          {
             $exchange->setStateValidation(LetsExchangeTable::STATE_ACCEPTED);
             $exchange->setDateValidation(date('Y-m-d'));
             $exchange->save();
             $this->getUser()->setFlash('notice',"Echange N°".$exchange->getId()." enregistré et accepté directement par votre partenaire.");
             $this->redirect('@lets_home_member');
          }
          else
          {
            $msgDisplay = 'mot de passe du partenaire invalide, ';
          }
        }
        // no direct validation
        $exchange->setStateValidation(LetsExchangeTable::STATE_NOT_VALIDATED);
      }
      

      $exchange->save();
      if($isExchangeCreation)
      {

        if($otherMember->hasEmail())
        {
          $msgDisplay .="un email demandant à votre partenaire de confirmer cet échange va être envoyé.";
          // notify partner
          MailerFactory::loadTemplateAndSend($myUserId,$otherMember,LetsManagerEmails::KEY_EXCHANGE_PENDING,array(
            'creator' => $myMember,
            'exchange.name' => $exchange->getName(),
            'exchange.amount' => ($exchange->getAmountWithSign($myUserId) * -1),
            'exchange.category' => $exchange->getCategory()->getName(),
            'exchange.money_name' => LetsConfiguration::moneyName($this->getUser()->getAssociationId()),
            'exchange.validation_link' => $this->generateUrl('lets_exchange_validate_link',
                array( 'member_id'=>$otherMember->getId(),'unique_key'=>$exchange->getUniqueKey()),true
             ),
          ));
        }
        else
        {
          $listExchangeManagers = LetsMemberTable::stringListExchangeManagers();
          $msgDisplay .= "votre partenaire ne disposant pas d'email, veuillez lui demander de contacter une des personnes suivantes [".
            $listExchangeManagers . "] pour valider l'échange.";
        }
        $this->getUser()->setFlash('notice','Echange N°'.$exchange->getId().' enregistré, '.$msgDisplay);
      }
      else{
        $this->getUser()->setFlash('notice','Echange N°'.$exchange->getId().' modifié.');
      }
      $this->redirect('@lets_home_member');
    }
  }
  
  protected function processFormManager(sfWebRequest $request, sfForm $form, LetsExchange $exchange = null)
  {
    $form->bind($request->getParameter($form->getName()));
    if ($form->isValid())
    {
      $values = $this->form->getValues();
      $myUserId = $this->getUser()->getUserId();
      if($exchange->isNew())
      {
        $can_add_others = $this->getUser()->hasPermission(LetsManagerRights::ADD_EXCHANGE_OTHERS);
        // user can't add exchange for others he is adding to asssociation debitor
        if(! $can_add_others)
        {
          $debitorAccountId = LetsMoneyAccountTable::getAccountIdByAssociationId($this->getUser()->getAssociationId());
        }
        else {
          $debitorAccountId = LetsMoneyAccountTable::getAccountIdByMemberId($values['debitor_id']);
        }
        $creditorAccoundId = LetsMoneyAccountTable::getAccountIdByMemberId($values['creditor_id']);
        $exchange->setDebitorId($debitorAccountId);
        $exchange->setCreditorId($creditorAccoundId);
        $exchange->setCreatedBy($myUserId);
        $exchange->setDateExchange($values['date_exchange']);
        // if the debitor is association account the exchange is directly validated
        if( (!$can_add_others) || (isset($values['state_validated']) && $values['state_validated'] == 'true') )
        {
          $exchange->setStateValidation(LetsExchangeTable::STATE_ACCEPTED);
          $exchange->setDateValidation(date('Y-m-d'));
        }
        else{
          $exchange->setStateValidation(LetsExchangeTable::STATE_NOT_VALIDATED);
        }
      } // end if new exchange
      $exchange->setName($values['name']);
      $exchange->setCategoryId($values['category_id']);
      $amount = abs(intval($values['amount']));
      $exchange->setAmount($amount);

      $exchange->save();
      $this->getUser()->setFlash('notice','Echange N°'.$exchange->getId().' enregistré');

      $this->redirect($this->getUser()->getCurrentReferer('@lets_exchanges_list'));
    }
  }
  
  protected function generateValidationKey(LetsExchange $exchange)
  {
    
    $str = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
    return $str;
  }
  
  
}